// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/signin/enterprise_profile_welcome_handler.h"

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/managed_ui.h"
#include "chrome/browser/ui/signin/profile_colors_util.h"
#include "chrome/browser/ui/signin_view_controller.h"
#include "chrome/browser/ui/webui/management/management_ui_handler.h"
#include "chrome/browser/ui/webui/signin/signin_utils.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/grit/generated_resources.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/strings/grit/components_strings.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image.h"
#include "ui/native_theme/native_theme.h"

namespace {
const int kAvatarSize = 100;

std::string GetManagedAccountTitle(ProfileAttributesEntry* entry,
                                   const std::string& fallback_domain_name) {
  DCHECK(entry);
  if (entry->GetHostedDomain() == kNoHostedDomainFound)
    return std::string();
  const std::string domain_name = entry->GetHostedDomain().empty()
                                      ? fallback_domain_name
                                      : entry->GetHostedDomain();
  return l10n_util::GetStringFUTF8(
      IDS_ENTERPRISE_PROFILE_WELCOME_ACCOUNT_MANAGED_BY,
      base::UTF8ToUTF16(domain_name));
}

std::string GetManagedAccountTitleWithEmail(
    ProfileAttributesEntry* entry,
    const std::string& fallback_domain_name,
    const std::u16string& email) {
  DCHECK(entry);
  DCHECK(!email.empty());
  if (entry->GetHostedDomain() == kNoHostedDomainFound)
    return std::string();
  const std::string domain_name = entry->GetHostedDomain().empty()
                                      ? fallback_domain_name
                                      : entry->GetHostedDomain();
  return l10n_util::GetStringFUTF8(
      IDS_ENTERPRISE_PROFILE_WELCOME_ACCOUNT_EMAIL_MANAGED_BY, email,
      base::UTF8ToUTF16(domain_name));
}

std::string GetManagedDeviceTitle() {
  absl::optional<std::string> device_manager =
      chrome::GetDeviceManagerIdentity();
  if (!device_manager)
    return std::string();
  if (device_manager->empty()) {
    return l10n_util::GetStringUTF8(
        IDS_ENTERPRISE_PROFILE_WELCOME_DEVICE_MANAGED);
  }
  return l10n_util::GetStringFUTF8(
      IDS_ENTERPRISE_PROFILE_WELCOME_DEVICE_MANAGED_BY,
      base::UTF8ToUTF16(*device_manager));
}

SkColor GetHighlightColor(absl::optional<SkColor> theme_color, bool dark_mode) {
  auto theme_colors =
      theme_color.has_value()
          ? GetProfileThemeColorsForAutogeneratedColor(*theme_color)
          : GetDefaultProfileThemeColors(dark_mode);
  return theme_colors.profile_highlight_color;
}

}  // namespace

EnterpriseProfileWelcomeHandler::EnterpriseProfileWelcomeHandler(
    Browser* browser,
    EnterpriseProfileWelcomeUI::ScreenType type,
    const AccountInfo& account_info,
    absl::optional<SkColor> profile_color,
    base::OnceCallback<void(bool)> proceed_callback)
    : browser_(browser),
      type_(type),
      email_(base::UTF8ToUTF16(account_info.email)),
      domain_name_(gaia::ExtractDomainName(account_info.email)),
      account_id_(account_info.account_id),
      profile_color_(profile_color),
      proceed_callback_(std::move(proceed_callback)) {
  DCHECK(proceed_callback_);
  DCHECK(
      browser_ ||
      type_ !=
          EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation);
  BrowserList::AddObserver(this);
}

EnterpriseProfileWelcomeHandler::~EnterpriseProfileWelcomeHandler() {
  BrowserList::RemoveObserver(this);
  HandleCancel(nullptr);
}

void EnterpriseProfileWelcomeHandler::RegisterMessages() {
  profile_path_ = Profile::FromWebUI(web_ui())->GetPath();
  web_ui()->RegisterDeprecatedMessageCallback(
      "initialized",
      base::BindRepeating(&EnterpriseProfileWelcomeHandler::HandleInitialized,
                          base::Unretained(this)));
  web_ui()->RegisterDeprecatedMessageCallback(
      "initializedWithSize",
      base::BindRepeating(
          &EnterpriseProfileWelcomeHandler::HandleInitializedWithSize,
          base::Unretained(this)));
  web_ui()->RegisterDeprecatedMessageCallback(
      "proceed",
      base::BindRepeating(&EnterpriseProfileWelcomeHandler::HandleProceed,
                          base::Unretained(this)));
  web_ui()->RegisterDeprecatedMessageCallback(
      "cancel",
      base::BindRepeating(&EnterpriseProfileWelcomeHandler::HandleCancel,
                          base::Unretained(this)));
}

void EnterpriseProfileWelcomeHandler::OnProfileAvatarChanged(
    const base::FilePath& profile_path) {
  UpdateProfileInfo(profile_path);
}

void EnterpriseProfileWelcomeHandler::OnProfileHighResAvatarLoaded(
    const base::FilePath& profile_path) {
  UpdateProfileInfo(profile_path);
}

void EnterpriseProfileWelcomeHandler::OnProfileHostedDomainChanged(
    const base::FilePath& profile_path) {
  UpdateProfileInfo(profile_path);
}

void EnterpriseProfileWelcomeHandler::OnBrowserRemoved(Browser* browser) {
  if (browser_ == browser)
    browser_ = nullptr;
}

void EnterpriseProfileWelcomeHandler::OnExtendedAccountInfoUpdated(
    const AccountInfo& info) {
  if (info.account_id == account_id_ && !info.account_image.IsEmpty()) {
    UpdateProfileInfo(profile_path_);
    observed_account_.Reset();
  }
}

void EnterpriseProfileWelcomeHandler::OnJavascriptAllowed() {
  if (type_ !=
      EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation) {
    observed_profile_.Observe(
        &g_browser_process->profile_manager()->GetProfileAttributesStorage());
  } else {
    observed_account_.Observe(
        IdentityManagerFactory::GetForProfile(Profile::FromWebUI(web_ui())));
  }
}

void EnterpriseProfileWelcomeHandler::OnJavascriptDisallowed() {
  observed_profile_.Reset();
  observed_account_.Reset();
}

void EnterpriseProfileWelcomeHandler::HandleInitialized(
    const base::ListValue* args) {
  CHECK_EQ(1u, args->GetList().size());
  AllowJavascript();
  const base::Value& callback_id = args->GetList()[0];
  ResolveJavascriptCallback(callback_id, GetProfileInfoValue());
}

void EnterpriseProfileWelcomeHandler::HandleInitializedWithSize(
    const base::ListValue* args) {
  AllowJavascript();

  if (browser_)
    signin::SetInitializedModalHeight(browser_, web_ui(), args);
}

void EnterpriseProfileWelcomeHandler::HandleProceed(
    const base::ListValue* args) {
  if (proceed_callback_)
    std::move(proceed_callback_).Run(true);
}

void EnterpriseProfileWelcomeHandler::HandleCancel(
    const base::ListValue* args) {
  if (proceed_callback_)
    std::move(proceed_callback_).Run(false);
}

void EnterpriseProfileWelcomeHandler::UpdateProfileInfo(
    const base::FilePath& profile_path) {
  DCHECK(IsJavascriptAllowed());
  if (profile_path != profile_path_)
    return;
  FireWebUIListener("on-profile-info-changed", GetProfileInfoValue());
}

base::Value EnterpriseProfileWelcomeHandler::GetProfileInfoValue() {
  base::Value dict(base::Value::Type::DICTIONARY);
  bool dark_mode =
      webui::GetNativeTheme(web_ui()->GetWebContents())->ShouldUseDarkColors();
  dict.SetStringKey("backgroundColor",
                    color_utils::SkColorToRgbaString(
                        GetHighlightColor(profile_color_, dark_mode)));
  dict.SetStringKey("pictureUrl", GetPictureUrl());

  std::string enterprise_title;
  std::string enterprise_info;
  ProfileAttributesEntry* entry = GetProfileEntry();

  switch (type_) {
    case EnterpriseProfileWelcomeUI::ScreenType::kEntepriseAccountSyncEnabled:
      dict.SetBoolKey("showEnterpriseBadge", true);
      enterprise_title = GetManagedAccountTitle(entry, domain_name_);
      enterprise_info = l10n_util::GetStringUTF8(
          IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITH_SYNC);
      dict.SetStringKey(
          "proceedLabel",
          l10n_util::GetStringUTF8(IDS_PROFILE_PICKER_IPH_NEXT_BUTTON_LABEL));
      break;
    case EnterpriseProfileWelcomeUI::ScreenType::kEntepriseAccountSyncDisabled:
      dict.SetBoolKey("showEnterpriseBadge", true);
      enterprise_title = GetManagedAccountTitle(entry, domain_name_);
      enterprise_info = l10n_util ::GetStringUTF8(
          IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITHOUT_SYNC);
      dict.SetStringKey("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE));
      break;
    case EnterpriseProfileWelcomeUI::ScreenType::kConsumerAccountSyncDisabled:
      dict.SetBoolKey("showEnterpriseBadge", false);
      enterprise_title = GetManagedDeviceTitle();
      enterprise_info =
          l10n_util::GetStringUTF8(IDS_SYNC_DISABLED_CONFIRMATION_DETAILS);
      dict.SetStringKey("proceedLabel", l10n_util::GetStringUTF8(IDS_DONE));
      break;
    case EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation:
      dict.SetBoolKey("showEnterpriseBadge", false);
      enterprise_title =
          GetManagedAccountTitleWithEmail(entry, domain_name_, email_);
      enterprise_info = l10n_util::GetStringUTF8(
          IDS_ENTERPRISE_PROFILE_WELCOME_MANAGED_DESCRIPTION_WITH_SYNC);
      dict.SetStringKey(
          "proceedLabel",
          l10n_util::GetStringUTF8(
              IDS_ENTERPRISE_PROFILE_WELCOME_CREATE_PROFILE_BUTTON));
  }

  dict.SetStringKey("enterpriseTitle", enterprise_title);
  dict.SetStringKey("enterpriseInfo", enterprise_info);

  return dict;
}

ProfileAttributesEntry* EnterpriseProfileWelcomeHandler::GetProfileEntry()
    const {
  ProfileAttributesEntry* entry =
      g_browser_process->profile_manager()
          ->GetProfileAttributesStorage()
          .GetProfileAttributesWithPath(profile_path_);
  DCHECK(entry);
  return entry;
}

std::string EnterpriseProfileWelcomeHandler::GetPictureUrl() {
  absl::optional<gfx::Image> icon;
  if (type_ ==
      EnterpriseProfileWelcomeUI::ScreenType::kEnterpriseAccountCreation) {
    AccountInfo account_info =
        IdentityManagerFactory::GetForProfile(Profile::FromWebUI(web_ui()))
            ->FindExtendedAccountInfoByAccountId(account_id_);
    DCHECK(!account_info.IsEmpty());
    icon = account_info.account_image.IsEmpty()
               ? ui::ResourceBundle::GetSharedInstance().GetImageNamed(
                     profiles::GetPlaceholderAvatarIconResourceID())
               : account_info.account_image;
  }

  const int avatar_icon_size = kAvatarSize * web_ui()->GetDeviceScaleFactor();
  return webui::GetBitmapDataUrl(
      profiles::GetSizedAvatarIcon(
          icon.value_or(GetProfileEntry()->GetAvatarIcon(avatar_icon_size)),
          true, avatar_icon_size, avatar_icon_size)
          .AsBitmap());
}

EnterpriseProfileWelcomeUI::ScreenType
EnterpriseProfileWelcomeHandler::GetTypeForTesting() {
  return type_;
}

void EnterpriseProfileWelcomeHandler::CallProceedCallbackForTesting(
    bool proceed) {
  if (proceed_callback_)
    std::move(proceed_callback_).Run(proceed);
}
